package com.linjiahao.oss.aop;

import com.alibaba.fastjson.JSON;
import com.linjiahao.oss.util.StateSecretSecurityUtil;
import com.linjiahao.oss.vo.SecurityParaVO;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 国密防泄漏AOP
 * @author suruihuang
 */
@Aspect
@Component
@Order(2)
public class StateSecretAntiLeakageAop {
    private final static transient Logger logger = LoggerFactory.getLogger(com.linjiahao.oss.aop.StateSecretAntiLeakageAop.class);

    @Autowired
    private StateSecretSecurityUtil stateSecretSecurityUtil;
    

    //启用国密标志,1:启用,0:禁用
    private static String ENABLE_STATE_SECRET="1";

    @Pointcut("(execution(* com.linjiahao.oss.service.*.*(..)))")
    private void antiLeakage() {}

    @Around("antiLeakage()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable{
       
        Date startTime=new Date();

        //执行方法前
        Signature signature = point.getSignature();
        // 方法名
        String methodName = signature.getName();
        // 类名
        String serviceName = signature.getDeclaringTypeName();
        // 参数名数组
        String[] parameterNames = ((MethodSignature) signature).getParameterNames();

        Object args[]=point.getArgs();

        // 构造参数组集合
        List<Object> argList = stateSecretSecurityUtil.toListJSON(args);

        //需要加密的字段信息列表
        List<SecurityParaVO> paraList=null;
        if(args!=null&&args.length>0){
            //加密
            paraList=stateSecretSecurityUtil.dealEncrypt(args);
        }

        //执行方法
        Object result = point.proceed();

        //重置加密字段值为未加密值(调用DAO层方法后，避免原对象值被加密)
        stateSecretSecurityUtil.resetEncrypt(paraList);

        //执行方法后
        if(result!=null){
            //用于防止对象多次被引用造成重复解密
            Map<Object,String> existParaMap=new HashMap<Object,String>();
            if(paraList!=null){
                for(SecurityParaVO securityParaVO:paraList){
                    existParaMap.put(securityParaVO.getObj(),"");
                }
            }

            //解密
            stateSecretSecurityUtil.dealDecrypt(result,existParaMap);
        }

        //执行方法后
        Date endTime=new Date();
        try {
            logger.info("\n国密防泄漏AOP\n日志ID:{}\n类名:{}\n方法:{}\n请求参数:{}\n请求数据[{}]:{}\n返回数据[{}]:{}\n耗时:{}毫秒\n", Thread.currentThread().getId(),serviceName, methodName, JSON.toJSON(parameterNames), startTime, JSON.toJSON(argList),endTime,JSON.toJSON(result),endTime.getTime()-startTime.getTime());
        } catch (Exception e) {
            logger.error("国密防泄漏AOP记录日志失败: {}",e.getMessage());
        }

        argList.clear();
        argList=null;

        return result;
    }


}
